package com.zh.freechat.web;

import com.zh.freechat.common.req.TokenForm;
import com.zh.freechat.domain.auth.JwtService;
import com.zh.freechat.domain.auth.LoginUser;
import com.zh.freechat.domain.auth.UserTokenWrap;
import com.zh.freechat.domain.user.entity.ChatUser;
import com.zh.freechat.domain.user.service.ChatUserService;
import com.zh.freechat.domain.validcode.ValidateCodeService;
import com.zh.mycommon.value.RegexpConst;
import com.zh.mycommon.value.Tuple2;
import com.zh.webcommon.common.viewdata.ApiResult;
import com.zh.webcommon.common.auth.annotation.NonePermission;
import com.zh.webcommon.common.exception.NotAuthorizeException;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.CompletableFuture;

import static com.zh.webcommon.common.viewdata.ApiResult.fail;
import static com.zh.webcommon.common.viewdata.ApiResult.success;
import static com.zh.webcommon.HeaderConst.HEADER_AUTH;
import static com.zh.webcommon.HeaderConst.HEADER_AUTH_PREFIX;

/**
 * 登录相关API
 *
 * @author ZH
 * @date 18:18 2021/8/1
 */
@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/auth")
public class LoginController {
    private final ValidateCodeService verifyCodeService;
    private final ChatUserService userService;
    private final JwtService jwtService;

    @NonePermission
    @GetMapping("/code/sms")
    public ApiResult<String> smsCode(@RequestParam("signer") String phoneOrEmail) {
        Tuple2<String, String> smsCode = verifyCodeService.createSmsCode("number");

        //异步发送验证码
        CompletableFuture.runAsync(() -> {
            if (phoneOrEmail.matches(RegexpConst.REGEX_PHONE)) {
                log.debug("发送验证码{} 到 手机号{} ...", smsCode.v2(), phoneOrEmail);
            } else {
                log.warn("没有发送途径，无法发送验证码{} 到 {} ...", smsCode.v2(), phoneOrEmail);
            }
        });
        return success(smsCode.v1());
    }


    /**
     * 刷新token
     *
     * @return
     */
    @NonePermission
    @PostMapping("/refresh")
    public UserTokenWrap refreshToken(@RequestHeader(HEADER_AUTH) String token, @RequestBody @Valid TokenForm form) {
        form.setToken(token.replace(HEADER_AUTH_PREFIX, ""));

        try {
            jwtService.parseJwtToken(form.getToken());
            return new UserTokenWrap(form.getToken(), form.getRefresh_token(), null);
        } catch (ExpiredJwtException ex) {
            //只有token过期了，才允许刷新token
            try {
                String uid = jwtService.parseRefreshToken(form.getRefresh_token());
                ChatUser user = userService.findByUid(uid);

                var loginUser = new LoginUser(uid, user.getUsername(), user.getNickname(), user.getAvatarUrl(), List.of(user.getRole()), null);

                var jwtToken = jwtService.createJwtToken(loginUser);
                var refreshToken = jwtService.createRefreshToken(uid, user.getUsername());

                return new UserTokenWrap(jwtToken, refreshToken, null);
            } catch (JwtException iex) {
                throw new NotAuthorizeException("invalid_refresh_token");
            }
        }
    }

    /**
     * 检查用户登录状态
     *
     * @return
     */
    @NonePermission
    @GetMapping("/checking")
    public ApiResult<Boolean> isLoggedIn() {
        boolean isLogged = SecurityContextHolder.getContext().getAuthentication().isAuthenticated();
        return success(isLogged);
    }
}
